package net.zoneland.cas.spi.impl;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.zoneland.cas.CasAppHelper;
import net.zoneland.cas.util.ClientFutureConst;

public class CasConfigProvider4client extends CasConfigProviderDefaultImpl {
    /** Logger for this class */
    private static final Logger LOG = LoggerFactory.getLogger(CasConfigProvider4client.class);
    private static final String KEY_CAS_CLIENT_REMOTE_CONFIG_OFF = "cas.client_remote_config_off";
    private static final String CAS_CLIENT_CONFIG = System.getProperty("cas_client_config","cas-client.properties");
    private final boolean off = "true".equals(props.get(KEY_CAS_CLIENT_REMOTE_CONFIG_OFF));
    public CasConfigProvider4client() {
        super(CAS_CLIENT_CONFIG ,null);
      
        LOG.info(KEY_CAS_CLIENT_REMOTE_CONFIG_OFF + ":" + off);
        if (!off ) {
            if (timer == null) {
                remoteInitIf();
            } else {
                remoteInitByTimer();
            }
        }
    }

    private volatile boolean  remoteInitRunning = false;
    protected void remoteInitByTimer() {
        TimerTask task = new TimerTask() {

            @Override
            public void run() {
                remoteInitRunning = true;
                try {
                    remoteInitIf();
                }finally {
                    remoteInitRunning = false;
                }
            }
        };
        timer.schedule(task, 300);
    }

    private boolean casServerNotInited = true;
    private transient AtomicLong remoteConfigFailCount = new AtomicLong(0);

   private static final Object REMOTE_INIT_LOCK = new Object();
   
    private  void remoteInitIf() {
        synchronized (REMOTE_INIT_LOCK) {
        String casUrl = props.get("cas.casServerUrlPrefix");
        if (casUrl == null) {
            casUrl = casServerUrlPrefix;
        }
        if (casUrl != null) {
            try {
                Properties p = new Properties();
                URL url = new URL(casUrl + (casUrl.endsWith("/") ? "config" : "/config"));
                if (LOG.isDebugEnabled()) {
                    LOG.debug("loading cas client from:{}", url);
                }
                InputStream in = CasAppHelper.toCipherInputStreamIf(url.openStream(), true);
                try {
                    p.load(in);
                } finally {
                    in.close();
                }
                addProfileName("remoteConfig="+p.size());
                if (LOG.isDebugEnabled()) {
                    LOG.debug("cas client config:{}", p);
                }
                if (p.size() > 0) {
                    props.putAll((Map)p);
                }
                casServerNotInited = false;
            } catch (java.io.FileNotFoundException ex) {
                LOG.error(ex.getMessage());
                casServerNotInited = false;
                LOG.warn("make sure the config is ok :" + ClientFutureConst.getConfig());
                remoteConfigFailCount.incrementAndGet();
            } catch (IOException ex) {
                LOG.error("{}", ex.getMessage(), ex);
                remoteConfigFailCount.incrementAndGet();
            }
        } else {
            casServerNotInited = false;
        }
        }
    }

    private static String casServerUrlPrefix;

    public static void setCasServerUrlPrefix(String casServerUrlPrefix) {
        CasConfigProvider4client.casServerUrlPrefix = casServerUrlPrefix;
    }

    private static Timer timer;

    public static void setTimer(Timer timer) {
        if (CasConfigProvider4client.timer != null) {
            CasConfigProvider4client.timer.cancel();
        }
        CasConfigProvider4client.timer = timer;
    }

    @Override
    public String getProperty(String p, String defaultValue) {
        if (casServerNotInited  && !off &&  timer == null && remoteConfigFailCount.get() < 10) {
            remoteInitIf();
        }
        return super.getProperty(p, defaultValue);
    }
}
